// 这个是客户端
// 客户端要给服务端发消息 , 二者要通信 !

#if 0 
    //客户端必须要知道的 : 
    1. 客户端需不需绑定 IP和端口号 ??? 
    答 : 需要绑定 , 但是不需要显示绑定 !!!
    2. 客户端是知道服务端的 IP和端口号的 , 因为用户输入了 
    但是 , 不需要我们显示 bind !!! 
    因为知道IP和端口 所以 , 系统会自己绑定 !!
    因为客户端很多 , 为了端口号不冲突 , 所以要自动分配 !!

#endif

#include <iostream>
#include <string>

// 网路4大剑客
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#include "Log.hpp"
using namespace LogModel;

// 客服端怎么使用 ?? 要知道服务端的IP和端口号吧 ??

// ./client server_ip server_port
// 引入命令行参数
int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        LOG(LogLevel::WARNING) << "Use : server_ip server_port ";
    }

    // 我们在命令行输入的都是字符串 , 所以要转化为对于类型
    std::string server_ip = argv[1];
    uint16_t server_port = std::stoi(argv[2]);

    // 那客户端干嘛呀  ??? 要给服务端发消息
    // 所以 , 客户端也要创建 套接字 , 这样才能从网络中获取

    // 【1.】 创建套接字  -- UDP
    int sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd < 0)
    {
        LOG(LogLevel::FATAL) << "socket error !";
        exit(1);
    }
    LOG(LogLevel::FATAL) << "socket success , sockfd : " << sockfd;

    // 【2.】 绑定 ??? 客户端需不需要绑定 ?? 需要 , 但是不需要我们显示绑定

    // 填充网络信息
    struct sockaddr_in local;
    local.sin_family = AF_INET;
    // 这个IP是从本地获取的 , 用户给的是字符串的
    // 要把IP转换成 4 字节的
    // 这里推荐用  int inet_pton(int af, const char *src, void *dst);
    // 即 : 进程转换网络 -- 即 , 本地转网络
    local.sin_addr.s_addr = inet_addr(server_ip.c_str());
    local.sin_port = htons(server_port);

    // 【3.】 客户端要发消息 --- 用接口 sendto , 所以要知道网络信息
    //        服务端回显消息给客户端 
    while (true)
    {
        std::string input;
        std::cout << "Please Enter# ";
        std::getline(std::cin, input);

        // 1 . 发
        //ssize_t sendto(int sockfd, const void *buf, size_t len, int flags,
                    //   const struct sockaddr *dest_addr, socklen_t addrlen);

       
        int n = sendto(sockfd , input.c_str() , input.size() , 0 , (struct sockaddr*)&local, sizeof(local));
        if(n > 0)
        {
            //发成功了 

            //2. 收 
            //接口 -- recvfrom , 接受的谁的消息啊 ?? 远端的 
            char buffer[1024];
            struct sockaddr_in peer;
            socklen_t len = sizeof(peer);
            ssize_t rcnum = recvfrom(sockfd ,buffer , sizeof(buffer)-1 ,0, (struct sockaddr*)&peer , &len);
            if(rcnum > 0)
            {
                //接受到了实际的数 
                buffer[rcnum] = 0;
                std::string echo_string = "echo@ ";
                std::string RecvString = echo_string += buffer;
                LOG(LogLevel::INFO) << RecvString ;
            }
        }
    }
        return 0;
    }